package com.sbc.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.sbc.cache.DistributedCache;
import com.sbc.common.toolkit.BeanUtil;
import com.sbc.convention.exception.ServiceException;
import com.sbc.user.dao.entity.TPassenger;
import com.sbc.user.dao.mapper.TPassengerMapper;
import com.sbc.user.pojo.vo.PassengerReqVo;
import com.sbc.user.pojo.vo.PassengerRespVo;
import com.sbc.user.service.PassengerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.sbc.user.constant.RedisKeyConstant.USER_PASSENGER_LIST;

/**
 * @description: 乘车人接口实现层
 * @author: songbaicheng
 * @create: 2024-05-02 23:24
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class PassengerServiceImpl implements PassengerService {

    private final DistributedCache distributedCache;
    private final TPassengerMapper passengerMapper;
    private final PlatformTransactionManager transactionManager;

    @Override
    public List<PassengerRespVo> queryPassengerByUsernameList(String username) {
        String actualUserPassengerListStr = getActualUserPassengerListStr(username);
        return Optional.ofNullable(actualUserPassengerListStr)
                .map(each -> JSON.parseArray(each, TPassenger.class))
                .map(each -> BeanUtil.convert(each, PassengerRespVo.class))
                .orElse(null);
    }

    @Override
    public void addPassenger(String username, PassengerReqVo requestParam) {
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);

        try {
            TPassenger passenger = BeanUtil.convert(requestParam, TPassenger.class);
            passenger.setCreateDate(LocalDate.now());
            passenger.setUsername(username);
            int insert = passengerMapper.insert(passenger);
            if (!SqlHelper.retBool(insert)) {
                throw new ServiceException(String.format("[%s] 新增乘车人失败", username));
            }
            transactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            if (ex instanceof ServiceException) {
                log.error("{}，请求参数：{}", ex.getMessage(), JSON.toJSONString(requestParam));
            } else {
                log.error("[{}] 新增乘车人失败，请求参数：{}", username, JSON.toJSONString(requestParam), ex);
            }
            transactionManager.rollback(transactionStatus);
            throw ex;
        }
        delUserPassengerCache(username);
    }

    @Override
    public void updatePassenger(String username, String id, PassengerReqVo requestParam) {
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
        try {
            TPassenger passengerDO = BeanUtil.convert(requestParam, TPassenger.class);
            passengerDO.setUsername(username);
            LambdaUpdateWrapper<TPassenger> updateWrapper = Wrappers.lambdaUpdate(TPassenger.class)
                    .eq(TPassenger::getId, id);
            int updated = passengerMapper.update(passengerDO, updateWrapper);
            if (!SqlHelper.retBool(updated)) {
                throw new ServiceException(String.format("[%s] 修改乘车人失败", username));
            }
            transactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            if (ex instanceof ServiceException) {
                log.error("{}，请求参数：{}", ex.getMessage(), JSON.toJSONString(requestParam));
            } else {
                log.error("[{}] 修改乘车人失败，请求参数：{}", username, JSON.toJSONString(requestParam), ex);
            }
            transactionManager.rollback(transactionStatus);
            throw ex;
        }
        delUserPassengerCache(username);
    }

    @Override
    public void deletePassenger(String username, String id) {
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);

        try {
            LambdaUpdateWrapper<TPassenger> deleteWrapper = Wrappers.lambdaUpdate(TPassenger.class)
                    .eq(TPassenger::getId, id);
            // 逻辑删除，修改数据库表记录 del_flag
            int deleted = passengerMapper.delete(deleteWrapper);
            if (!SqlHelper.retBool(deleted)) {
                throw new ServiceException("删除乘车人失败");
            }
            transactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            if (ex instanceof ServiceException) {
                log.error("{}", ex.getMessage());
            } else {
                log.error("删除乘车人失败：{}", ex.getMessage());
            }
            transactionManager.rollback(transactionStatus);
            throw ex;
        }
        delUserPassengerCache(username);
    }

    /**
     * 安全获取用户乘车人列表字符串
     *
     * @param username 用户名
     * @return 乘车人列表字符串
     */
    private String getActualUserPassengerListStr(String username) {
        return distributedCache.safeGet(
                USER_PASSENGER_LIST + username,
                String.class,
                () -> {
                    LambdaQueryWrapper<TPassenger> queryWrapper = Wrappers.lambdaQuery(TPassenger.class)
                            .eq(TPassenger::getUsername, username);
                    List<TPassenger> passengers = passengerMapper.selectList(queryWrapper);
                    return CollUtil.isNotEmpty(passengers) ? JSON.toJSONString(passengers) : null;
                },
                1,
                TimeUnit.DAYS
        );
    }

    /**
     * 删除缓存中指定用户乘车人信息
     *
     * @param username 用户名
     */
    private void delUserPassengerCache(String username) {
        distributedCache.delete(USER_PASSENGER_LIST + username);
    }
}
